package com.yuandian.customer.perception.controller;

import cn.hutool.core.date.DateUtil;
import com.yuandian.api.customer_perception.po.OperatorOverviewParams;
import com.yuandian.api.customer_perception.vo.*;
import com.yuandian.api.management.feign.RemoteAreaService;
import com.yuandian.api.management.feign.RemoteBusinessHallService;
import com.yuandian.base.service.ITaskDataService;
import com.yuandian.bpm.common.core.constant.CommonConstants;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.customer.perception.service.IOperatorOverviewService;
import com.yuandian.enums.TableNameEnum;
import com.yuandian.po.MultipleTableInfo;
import com.yuandian.utils.PageDataInfo;
import com.yuandian.utils.StringUtils;
import com.yuandian.utils.YDateUtil;
import com.yuandian.utils.poi.ExcelTitleUtils;
import com.yuandian.utils.poi.ExcelUtil;
import com.yuandian.vo.TrendDataVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * <p>
 * 操作员监控总览
 * <p>
 *
 * @author lijunhang
 * @date 2021/8/16
 * @since 1.0.0
 */
@Slf4j
@Api(value = "操作员监控总览接口", tags = "操作员监控总览接口")
@RestController
@RequestMapping("/operator/operatorMonitor")
public class OperatorMonitorController {


    @Autowired
    private IOperatorOverviewService operatorOverviewService;

    @Autowired
    private ITaskDataService taskDataService;

    @Autowired
    private RemoteAreaService remoteAreaService;

    @Autowired
    private RemoteBusinessHallService remoteBusinessHallService;

    /**
     * 操作员总览列表
     *
     * @param params  请求参数 请求参数
     * @return  结果集 操作员总览列表数据
     */
	@ApiOperation(value = "操作员监控总览-操作员总览列表", notes = "操作员监控总览-操作员总览列表")
	@PostMapping("/operatorOverviewList")
    public R<Object> operatorOverviewList(@RequestBody OperatorOverviewParams params) {
		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.ADS_BUSI_SYS_VISIT_TREND_M.getName());
		List<MultipleTableInfo> tableInfos = Collections.singletonList(info);

        return R.ok(operatorOverviewService.operatorOverviewList(params, tableInfos));
    }

    /**
     * 操作员总览列表下载
     *
     * @param params  请求参数 请求参数
     * @return  结果集 操作员总览列表数据
     */
	@ApiOperation(value = "操作员监控总览-操作员总览列表下载", notes = "操作员监控总览-操作员总览列表下载")
	@PostMapping("/operatorOverviewListExport")
    public void operatorOverviewListExport(@RequestBody OperatorOverviewParams params, HttpServletResponse response) throws IOException {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> tableInfos = Collections.singletonList(info);

		List<OperatorOverviewVo> list = new ArrayList<>();
        try {
            list = operatorOverviewService.operatorOverviewListExport(params, tableInfos);
        } catch (Exception e) {
            log.error("所选时间表不存在!但表格需要正常导出.");
        }
        // 微秒转毫秒
        list.forEach(operatorOverviewVo -> {
            if (StringUtils.isBlank(operatorOverviewVo.getBusinessHallName())) {
                operatorOverviewVo.setBusinessHallName("未知");
            }
            if (StringUtils.isBlank(operatorOverviewVo.getAreaName())) {
                operatorOverviewVo.setAreaName("未知");
            }

            if (operatorOverviewVo.getAvgAllTime() !=  null && !("").equals(operatorOverviewVo.getAvgAllTime())) {
                operatorOverviewVo.setAvgAllTime(YDateUtil.getMinSecond(getDouble(Double.parseDouble(operatorOverviewVo.getAvgAllTime()) / 1000)));
            }
            if (operatorOverviewVo.getAvgResponseTime() !=  null && !("").equals(operatorOverviewVo.getAvgResponseTime())) {
                operatorOverviewVo.setAvgResponseTime(YDateUtil.getMinSecond(getDouble(Double.parseDouble(operatorOverviewVo.getAvgResponseTime()) / 1000)));
            }
            if (operatorOverviewVo.getAvgVisitTime() !=  null && !("").equals(operatorOverviewVo.getAvgVisitTime())&& !("-").equals(operatorOverviewVo.getAvgVisitTime())) {
                operatorOverviewVo.setAvgVisitTime(YDateUtil.getMinSecond(getDouble(Double.parseDouble(operatorOverviewVo.getAvgVisitTime()) / 1000)));
            }
            if (operatorOverviewVo.getSuccessRate() !=  null && !("").equals(operatorOverviewVo.getSuccessRate())) {
                operatorOverviewVo.setSuccessRate(operatorOverviewVo.getSuccessRate() + "%");
            }

        });

        String title = "操作员总览列表";
        String fileName = title + System.currentTimeMillis();
        List<String> titleParams = new ArrayList<>();
        titleParams.add(title);
        if (params.getAreaCode() !=  null && !"".equals(params.getAreaCode())) {
            R<String> nameRes = remoteAreaService.queryAreaName(params.getAreaCode());
            if (nameRes.getCode() == CommonConstants.FAIL){
                log.error("远程调用配置系统获取区域名称失败,错误：{}",nameRes.getMsg());
            }
            titleParams.add(nameRes.getData());
        }
        if (params.getBusinessHallId() !=  null && !"".equals(params.getBusinessHallId())) {
            R<String> nameRes = remoteBusinessHallService.queryBusinessHallNameById(params.getBusinessHallId());
            if (nameRes.getCode() == CommonConstants.FAIL){
                log.error("远程调用配置系统获取营业厅名称失败,错误：{}",nameRes.getMsg());
            }
            titleParams.add(nameRes.getData());
        }
        String formTitleName = ExcelTitleUtils.formTitleName(titleParams,params.getStartTime(),params.getEndTime());

        List<List<String>> headList = new ArrayList<>();
        List<String> titleList = Arrays.asList("序号", "地市",params.getOfficeName()+"ID",params.getOfficeName()+"名称", "操作员ID", "姓名", "系统使用数量", "业务使用数量", "访问量", "受理量"
                , "业务失败量", "业务告警量", "平均办理时长", "人工操作平均耗时", "系统响应平均耗时", "成功率");
        String finalFormTitleName = formTitleName;
        titleList.forEach(s -> {
            List<String> childHeadList = new ArrayList<>();
            childHeadList.add(finalFormTitleName);
            childHeadList.add(s);
            headList.add(childHeadList);
        });
        // 回填序号
        int index = 1;
        for (OperatorOverviewVo operatorOverviewVo : list) {
            operatorOverviewVo.setId(index++);
        }
        ExcelUtil.writeExcel(OperatorOverviewVo.class, fileName, title, list, headList, response);
    }


    /**
     * 营业厅下拉框接口
     *
     * @param areaCode 请求参数
     * @return  结果集
     */
	@ApiOperation(value = "操作员监控总览-营业厅下拉框接口", notes = "操作员监控总览-营业厅下拉框接口")
	@GetMapping("/queryBusinessHall")
    public R<Object> queryBusinessHall(@RequestParam(name = "areaCode", required=false ) String areaCode) {
        OperatorOverviewParams params = new OperatorOverviewParams();
        if (areaCode != null && !"".equals(areaCode)) {
            params.setAreaCode(areaCode);
        }
        return R.ok(operatorOverviewService.queryBusinessHall(params));
    }



    /**
     * 营业厅下拉框接口
     *
     * @param params  请求参数 请求参数
     * @return  结果集
     */
	@ApiOperation(value = "操作员监控总览-营业厅下拉框接口", notes = "操作员监控总览-营业厅下拉框接口")
	@PostMapping("/queryBusinessHall2")
    public R<Object> queryBusinessHall2(@RequestBody OperatorOverviewParams params) {
        return R.ok(operatorOverviewService.queryBusinessHall2(params));
    }

    /**
     * 查询全系统操作员总数，当前在线操作员数量
     *
     * @param params  请求参数 请求参数
     * @return  结果集 查询全系统操作员总数，当前在线操作员数量
     */
	@ApiOperation(value = "操作员监控总览-查询全系统操作员总数，当前在线操作员数量", notes = "操作员监控总览-查询全系统操作员总数，当前在线操作员数量")
	@PostMapping("/queryOperatorCount")
    public R<Object> queryOperatorCount(@RequestBody  OperatorOverviewParams params) {
		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.ADS_BUSI_SYS_VISIT_TREND_M.getName());
		List<MultipleTableInfo> tableInfos = Collections.singletonList(info);

        OperatorCountVo operatorCountVo = new OperatorCountVo();
        int totalOperatorOnline = operatorOverviewService.operatorOnlineNum(params, tableInfos);

        operatorCountVo.setTotalOperatorOnline(totalOperatorOnline);
        return R.ok(operatorCountVo);
    }


    /**
     * 操作员业务受理量top5
     *
     * @param params  请求参数 请求参数
     * @return  结果集 操作员业务受理量top5数据
     */
	@ApiOperation(value = "操作员监控总览-操作员业务受理量top5", notes = "操作员监控总览-操作员业务受理量top5")
	@PostMapping("/operatorCompleteTop5")
    public R<Object> operatorCompleteTop5(@RequestBody  OperatorOverviewParams params) throws ParseException {
		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.ADS_BUSI_SYS_VISIT_TREND_M.getName());
		List<MultipleTableInfo> tableInfos = Collections.singletonList(info);

        List<OperatorCompleteTopVo> list = operatorOverviewService.operatorCompleteTop5(params, null, tableInfos);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date startTime = simpleDateFormat.parse(params.getStartTime());
        Date endTime = simpleDateFormat.parse(params.getEndTime());
        if (YDateUtil.isSameDay(startTime, endTime)) {
            // 开始时间和结束时间减去一天
            String yesterdayStartTime = YDateUtil.getPastDate2(params.getStartTime(), 1, YDateUtil.YYYY_MM_DD_HH_MM_SS);
            String yesterdayEndTime = YDateUtil.getPastDate2(params.getEndTime(), 1, YDateUtil.YYYY_MM_DD_HH_MM_SS);
            params.setStartTime(yesterdayStartTime);
            params.setEndTime(yesterdayEndTime);

            tableInfos = Collections.singletonList(info);



            ArrayList<String> operatorIds = new ArrayList<>();
            list.forEach(operatorCompleteTopVo -> {
                String operatorId = operatorCompleteTopVo.getOperatorId();
                operatorIds.add(operatorId);
            });
            List<OperatorCompleteTopVo> singleList = operatorOverviewService.operatorCompleteTop5(params,operatorIds, tableInfos);
            for (int i = 0; i < singleList.size() && i < list.size(); i++) {
                list.get(i).setYesterdaySuccessCount(singleList.get(i).getSuccessCount());
                list.get(i).setYesterdayFailCount(singleList.get(i).getFailCount());
            }
        }
        return R.ok(list);
    }

    /**
     * 操作员业务受理量top5
     *
     * @param params  请求参数 请求参数
     * @return  结果集 操作员业务受理量top5数据
     */
	@ApiOperation(value = "操作员监控总览-操作员业务受理量top5", notes = "操作员监控总览-操作员业务受理量top5")
	@PostMapping("/operatorCompleteTimeTop5")
    public R<Object> operatorCompleteTimeTop5(@RequestBody  OperatorOverviewParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.ADS_BUSI_SYS_VISIT_TREND_M.getName());
		List<MultipleTableInfo> tableInfos = Collections.singletonList(info);

        return R.ok(operatorOverviewService.operatorCompleteTimeTop5(params, tableInfos));
    }


    /**
     * 操作员活跃数趋势
     * 当前活跃数量,昨日活跃数量-busi_operator_online_stat-OperatorDetailTask-操作员活跃数量趋势图-延迟0分钟-/api-khgz/home/index/operatorActiveCountTrend
     * @param params  请求参数 请求参数
     * @return  结果集 数据
     */
	@ApiOperation(value = "操作员监控总览-操作员活跃数趋势", notes = "操作员监控总览-操作员活跃数趋势")
	@PostMapping("/operatorActiveCountTrend")
    public R<Object> operatorActiveCountTrend(@RequestBody  OperatorOverviewParams params) {
        TrendDataVo trendDataVo = taskDataService.getTrendObject("KHGZ-营业员在线数量统计", params.getStartTime(), params.getEndTime(), null);
        if (trendDataVo.isLastShow()) {
			params.setEndTime(YDateUtil.parseDateToStr(YDateUtil.YYYY_MM_DD_HH_MM_SS,
					new Date(DateUtil.parse(trendDataVo.getTrendEndTime(), YDateUtil.YYYY_MM_DD_HH_MM_SS).getTime()+60*1000)));
		}

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> tableInfos = Collections.singletonList(info);
        List<OperatorActiveCountVo> operatorActiveCountVos = operatorOverviewService.operatorActiveCount(params, tableInfos);
        return R.ok(operatorActiveCountVos);
    }


    /**
     * 操作员违规告警提示列表
     *
     * @param params  请求参数 请求参数
     * @return  结果集 操作员违规告警提示列表数据
     */
	@ApiOperation(value = "操作员监控总览-操作员违规告警提示列表", notes = "操作员监控总览-操作员违规告警提示列表")
	@PostMapping("/operatorViolationList")
    public R<Object> operatorViolationList(@RequestBody OperatorOverviewParams params) {
		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.ADS_BUSI_SYS_VISIT_TREND_M.getName());
		List<MultipleTableInfo> tableInfos = Collections.singletonList(info);

        // 查询最近违规时间、操作员id、操作员姓名
        List<OperatorViolationVo> list = operatorOverviewService.operatorViolationListExport(params);
        // 回填营业厅id、营业厅名称、区域编码
        List<String> operators = new ArrayList<>();
        list.forEach(operatorViolationVo -> {
            if (StringUtils.isNotBlank(operatorViolationVo.getOperatorId())) {
                operators.add(operatorViolationVo.getOperatorId());
            }
        });
        // 回填最近一个月违规次数最多的业务,一次性查询，再根据操作员id回填业务名城
        List<OperatorViolationVo> list1  = operatorOverviewService.operatorBusinessName(params,operators);
        HashMap<String,String> hashMap = new HashMap<>();
        list1.forEach(operatorViolationVo -> {
            hashMap.put(operatorViolationVo.getOperatorId(),operatorViolationVo.getBusinessName());
        });
        // 回填最近上线时间
        List<OperatorViolationVo> operatorViolationVos = operatorOverviewService.queryOnlineTimeByOperatorId(params,operators, tableInfos);
        HashMap<String,OperatorViolationVo> operatorViolationVoMaps = new HashMap<>();
        operatorViolationVos.forEach(operatorViolationVo -> {
            operatorViolationVoMaps.put(operatorViolationVo.getOperatorId(),operatorViolationVo);
        });
        list.forEach(operatorViolationVo -> {
            // 开始时间往前推一个月
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar calendar = Calendar.getInstance();
            try {
                Date dd = df.parse(params.getStartTime());
                calendar.setTime(dd);
                calendar.add(Calendar.MONTH, -1);
            }catch (Exception e) {
                e.printStackTrace();
            }
            String st = df.format(calendar.getTime());
            st = st+" 00:00:00";
            operatorViolationVo.setBeforeMonthStartTime(st);
            if (operatorViolationVoMaps.get(operatorViolationVo.getOperatorId())!= null) {
                // 格式化最近上线时间，最近违规时间
                if (StringUtils.isNotBlank(operatorViolationVo.getLastOperateTime())) {
                    operatorViolationVo.setLastOperateTime(operatorViolationVo.getLastOperateTime().replace(".0",""));
                }
                if (StringUtils.isNotBlank(operatorViolationVoMaps.get(operatorViolationVo.getOperatorId()).getLastOnlineTime())) {
                    operatorViolationVo.setLastOnlineTime(operatorViolationVoMaps.get(operatorViolationVo.getOperatorId()).getLastOnlineTime().replace(".0",""));
                }
                operatorViolationVo.setBusinessName(hashMap.get(operatorViolationVo.getOperatorId()));
            }
        });


        // 根据地区编码和营业厅编码过滤数据
        if (StringUtils.isNotBlank(params.getAreaCode())) {
            for (Iterator<OperatorViolationVo> iterator = list.iterator(); iterator.hasNext();) {
                if (!params.getAreaCode().equals(iterator.next().getAreaCode())) {
                    iterator.remove();
                }
            }
        }
        if (StringUtils.isNotBlank(params.getBusinessHallId())) {
			list.removeIf(operatorViolationVo -> !params.getBusinessHallId().equals(operatorViolationVo.getBusinessHallId()));
        }

        // 对最近上线时间进行手动排序
        if ("lastOnlineTime".equals(params.getOrderByColumn())) {
            // 如果最新上线时间为空，则将元素移动到新数组，删除list的元素，排序完了再拼接回去
            List<OperatorViolationVo> tempNullList = new ArrayList<>();
            for (Iterator<OperatorViolationVo> iterator = list.iterator(); iterator.hasNext();) {
                OperatorViolationVo operatorViolationVo = iterator.next();
                if (StringUtils.isBlank(operatorViolationVo.getLastOnlineTime())) {
                    tempNullList.add(operatorViolationVo);
                    iterator.remove();
                }
            }
            if ("desc".equals(params.getIsAsc())) {
                list.sort((o1, o2) -> Objects.requireNonNull(YDateUtil.yyyy_MM_dd_HH_mm(o2.getLastOnlineTime())).compareTo(YDateUtil.yyyy_MM_dd_HH_mm(o1.getLastOnlineTime())));
            } else {
                list.sort(Comparator.comparing(OperatorViolationVo::getLastOnlineTime));
            }
            list.addAll(tempNullList);
        }

        List<OperatorViolationVo> pageList = getListPage((int) params.getPageNum(),(int)params.getPageSize(),list);

        if (list.size()!= 0) {
            PageDataInfo pageDataInfo = new PageDataInfo(list.size(),pageList);
            return R.ok(pageDataInfo);
        }else{
            return R.ok(new PageDataInfo(0,new ArrayList<>()));
        }

    }


    /**
     * 操作员违规告警提示列表下载
     *
     * @param params  请求参数 请求参数
     * @return  结果集 操作员违规告警提示列表数据
     */
	@ApiOperation(value = "操作员监控总览-操作员违规告警提示列表下载", notes = "操作员监控总览-操作员违规告警提示列表下载")
	@PostMapping("/operatorViolationListExport")
    public void operatorViolationListExport(@RequestBody OperatorOverviewParams params, HttpServletResponse response) throws IOException {
        String title = "最近一个月操作员违规告警提示列表";
        String fileName = title + System.currentTimeMillis();
        List<String> titleParams = new ArrayList<>();
        titleParams.add(title);
        if (params.getAreaCode() !=  null && !"".equals(params.getAreaCode())) {
            R<String> nameRes = remoteAreaService.queryAreaName(params.getAreaCode());
            if (nameRes.getCode() == CommonConstants.FAIL){
                log.error("远程调用配置系统获取区域名称失败,错误：{}",nameRes.getMsg());
            }
            titleParams.add(nameRes.getData());
        }
        if (params.getBusinessHallId() !=  null && !"".equals(params.getBusinessHallId())) {
            R<String> nameRes = remoteBusinessHallService.queryBusinessHallNameById(params.getBusinessHallId());
            if (nameRes.getCode() == CommonConstants.FAIL){
                log.error("远程调用配置系统获取营业厅名称失败,错误：{}",nameRes.getMsg());
            }
            titleParams.add(nameRes.getData());
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime startF = LocalDateTime.parse(params.getEndTime(), formatter);
        LocalDateTime minusMonths = startF.minusMonths(1);
        String startTimetemp = minusMonths.format(formatter);
        String formTitleName = ExcelTitleUtils.formTitleName(titleParams,startTimetemp,params.getEndTime());

        List<OperatorViolationVo> list = new ArrayList<>();
        try {
            params.setPageNum(-1);
            list = (List<OperatorViolationVo>)((PageDataInfo) operatorViolationList(params).getData()).getData();
        } catch (Exception e) {
            log.error("所选时间表不存在!但表格需要正常导出.");
        }

        List<List<String>> headList = new ArrayList<>();
        List<String> titleList = Arrays.asList("序号",params.getOfficeName()+"ID", params.getOfficeName()+"名称","操作员ID", "姓名", "违规业务", "最近上线时间", "最近违规时间");
        titleList.forEach(s -> {
            List<String> childHeadList = new ArrayList<>();
            childHeadList.add(formTitleName);
            childHeadList.add(s);
            headList.add(childHeadList);
        });
        // 回填序号
        int index = 1;
        for (OperatorViolationVo vo : list) {
            vo.setId(index++);
            // 处理数据,分情况回填未知
            if (vo.getBusinessHallId() == null || vo.getBusinessHallId().equals("")) {
                vo.setBusinessHallId("-");
            }
            if (vo.getBusinessHallName() == null || vo.getBusinessHallName().equals("")) {
                if (Objects.equals(vo.getBusinessHallId(), "-")) {
                    vo.setBusinessHallName("-");
                } else {
                    vo.setBusinessHallName("未知");
                }
            }
            if (vo.getOperatorId() == null || vo.getOperatorId().equals("")) {
                vo.setOperatorId("-");
            }
            if (vo.getOperatorName() == null || vo.getOperatorName().equals("")) {
                if (Objects.equals(vo.getOperatorId(), "-")) {
                    vo.setOperatorName("-");
                } else {
                    vo.setOperatorName("未知");
                }
            }
        }
        ExcelUtil.writeExcel(OperatorViolationVo.class, fileName, title, list, headList, 25, response);
    }

    private static Double getDouble(Double allTime) {
        if (allTime == null) {
            return 0d;
        }
        return new BigDecimal(allTime).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }


    /**
     * list手动分页
     * @param page
     * @param pageSize
     * @param list
     * @return  结果集
     */
    private List<OperatorViolationVo> getListPage(int page,int pageSize,List<OperatorViolationVo> list) {
        if (list == null || list.size() == 0) {
            return new ArrayList<>();
        }
        if (page == -1) {
            return list;
        }
        int totalCount = list.size();
        page = page -1;
        int fromIndex = page * pageSize;
        // 分页不能大于总数
//         if (fromIndex >= totalCount) {
//             throw new RuntimeException("页数或分页大小不正确");
//         }
        int toIndex = ((page+1) * pageSize);
        if (toIndex>totalCount) {
            toIndex = totalCount;
        }
        return list.subList(fromIndex, toIndex);
    }

}
